package top.lingkang.finalgateway.core.ssl;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.ssl.SslHandler;
import lombok.extern.slf4j.Slf4j;
import top.lingkang.finalgateway.core.DispatcherHandler;
import top.lingkang.finalgateway.core.FinalHttpObjectAggregator;
import top.lingkang.finalgateway.utils.SslUtils;

import javax.net.ssl.SSLEngine;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 实现 http 自动重定向到 https
 *
 * @author lingkang
 * @create by 2024/5/16 11:31
 */
@Slf4j
public class RedirectToJksHttpsHandler extends ByteToMessageDecoder {

    private final SslJksServerInitHandler handler;

    public RedirectToJksHttpsHandler(SslJksServerInitHandler handler) {
        this.handler = handler;
    }

    private static final byte[] httpsTip;

    static {
        String https = "HTTP/1.1 500 Internal Server Error\n" +
                "Content-Type: text/html\n" +
                "Content-Length: 235\n" +
                "Connection: close\n" +
                "\n\r\n" +
                "<!DOCTYPE html>\n" +
                "<html>\n" +
                "<body>\n" +
                "请使用https访问: <a href=\"javascript:;\" onclick=\"https()\">https</a>\n" +
                "<script>\n" +
                "    function https() {\n" +
                "        window.location.href = window.location.href.replace('http:', 'https:')\n" +
                "    }\n" +
                "</script>\n" +
                "</body>\n" +
                "</html>";
        httpsTip = https.getBytes(StandardCharsets.UTF_8);
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf byteBuf, List<Object> list) throws Exception {
        ByteBuf slice = byteBuf.slice(0, Math.min(byteBuf.readableBytes(), 64));
        byte[] bytes = ByteBufUtil.getBytes(slice);
        if (bytes[0] != 22) {// http
            if (handler.config.getSslAddress() != null) {
                // https://lingkang.top/about
                String path = handler.config.getSslAddress() + SslUtils.getPath(new String(bytes));
                String str302 = "HTTP/1.1 302 Found\n" +
                        "Content-Type: text/html\n" +
                        "Content-Length: 0\n" +
                        "Location: " + path +
                        "\n\r\n";
                log.info("http重定向到https: {}", path);
                ctx.writeAndFlush(Unpooled.copiedBuffer(str302.getBytes())).addListener(ChannelFutureListener.CLOSE);
                ctx.fireChannelRead(byteBuf);
                return;
            } else {
                ctx.writeAndFlush(Unpooled.copiedBuffer(httpsTip)).addListener(ChannelFutureListener.CLOSE);
                ctx.fireChannelRead(byteBuf);
                return;
            }
        }
        // ssl处理
        SSLEngine engine = handler.sslContext.createSSLEngine();
        engine.setEnabledProtocols(handler.sslConfig.getEnableProtocols());
        engine.setEnabledCipherSuites(handler.sslConfig.getEnableCipherSuites());
        engine.setUseClientMode(false);
        ctx.pipeline().addLast(new SslHandler(engine));

        ctx.pipeline().addLast(new HttpServerCodec());// http编解码
        ctx.pipeline().addLast(new FinalHttpObjectAggregator(handler.config.getMaxContentLength()));
        ctx.pipeline().addLast(new DispatcherHandler(handler.config));

        // 移除当前解码
        ctx.pipeline().remove(this);
        // 进入下一个通道处理
        ctx.fireChannelActive();
    }
}
